using System;
using System.Collections.ObjectModel;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Silverlight.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
using SLNGP.Common.Extensions;
using SLNGP.Common.IoC;
using SLNGP.Core.Genes;
using SLNGP.Core.GeneticPrograms;
using SLNGP.Core.Individuals;
using SLNGP.Core.Run;
using SLNGP.Core.Test;

namespace SLNGP.Test.CoreTests.Individuals
{
    [TestClass]
    [Tag("Individual")]
    public class Individual_Test : UnitTestBase<IIndividual, Individual>
    {
        #region UnitTestBase methods
        [ClassInitialize]
        public static void ClassInitialize(TestContext testContext)
        {
            UnitTestBase<IIndividual, Individual>.ClassInitialize(testContext);
        }

        [ClassCleanup]
        public static void ClassCleanup()
        {
            UnitTestBase<IIndividual, Individual>.ClassCleanup();
        }

        [TestInitialize]
        public override void TestInitialize()
        {
            base.TestInitialize();
        }

        [TestCleanup]
        public override void TestCleanup()
        {
            base.TestCleanup();
        }
        #endregion UnitTestBase methods

        [TestMethod]
        public void Ctor_AddChromosomeToIoC_IndividualChromosomeIsTheMock()
        {
            // state - Ctor

            // action - AddChromosomeToIoC
            var chromosomeMock = mocks.DynamicMock<IChromosome>();
            IoC.Register<IChromosome>(chromosomeMock);

            // Expectation - IndividualChromosomeIsTheMock
            Assert.IsTrue(curElement.Chromosome == chromosomeMock);
        }

        [TestMethod]
        public void Ctor_AddChromosomeToIoC_ParentIndividualIsCurrentElement()
        {
            // state - Ctor

            // action - AddChromosomeToIoC
            var chromosomeMock = mocks.DynamicMock<IChromosome>();
            IoC.Register<IChromosome>(chromosomeMock);

            // Expectation - IndividualChromosomeIsTheMock
            using (mocks.Record())
                chromosomeMock.ParentIndividual = curElement;

            // verify
            var x = curElement.Chromosome;
            mocks.VerifyAll();
        }

        [TestMethod]
        public void IsValid_WithMockChromosome_IsValidInvokesChromosome()
        {
            // state - IsValid
            // action - WithMockChromosome
            var mock = mocks.DynamicMock<IChromosome>();
            IoC.Register<IChromosome>(mock);

            // Expectation - IsValidInvokesChromosome
            using (mocks.Record())
                Expect.Call(mock.IsValid).Return(true);

            // verify
            Assert.IsTrue(curElement.IsValid == true);
            mocks.VerifyAll();
        }

        [TestMethod]
        public void WithMockChromosome_Fix_CallsMockFix()
        {
            // state - WithMockChromosome
            var mock = mocks.DynamicMock<IChromosome>();
            IoC.Register<IChromosome>(mock);

            // Expectation - CallsMockFix
            using (mocks.Record())
                mock.Fix();

            // Action - Fix
            curElement.Fix();

            // verify
            mocks.VerifyAll();
        }

        [TestMethod]
        [Ignore()]
        [Bug("RhinoMocks bug where it cannot do Expect.Call on ToString for an interface.")]
        public void WithMockChromosome_ToString_CallsMockToStringAndReturnsIt()
        {
            // state - FixWithMockChromosome_
            var mock = mocks.DynamicMock<IChromosome>();
            IoC.Register<IChromosome>(mock);

            // Expectation - CallsMockFix
            using (mocks.Record())
                Expect.Call(mock.ToString()).Return(TestStrings[0]);

            // Action - invoke
            Assert.IsTrue(curElement.ToString() == TestStrings[0]);

            // verify
            mocks.VerifyAll();
        }

        //[TestMethod]
        //[Ignore("Refactoring made this test invalid. Which is fine.")]
        //public void WithMockChromosome_SetParentGeneticProgram_SetsMockChromosomeGeneticProgram()
        //{
        //    // state - WithMockChromosome
        //    var mock = mocks.DynamicMock<IChromosome>();
        //    IoC.Register<IChromosome>(mock);
        //    var mockGeneticProgram = mocks.StrictMock<IGeneticProgram>();

        //    // Expectation - SetsMockChromosomeGeneticProgram
        //    using (mocks.Record())
        //        mock.ParentGeneticProgram = mockGeneticProgram;

        //    // action - SetParentGeneticProgram
        //    curElement.ParentGeneticProgram = mockGeneticProgram;

        //    // verify
        //    mocks.VerifyAll();
        //}

        [TestMethod]
        public void ThreeNestedMockGenesWithMockChromoeRootGene_AllGenes_ReturnsAll3Genes()
        {
            // state - ThreeNestedMockGenesWithMockChromoeRootGene
            var mock = mocks.DynamicMock<IChromosome>();
            IoC.Register<IChromosome>(mock);
            var mockGene1 = mocks.DynamicMock<IGene>();
            var mockGene2 = mocks.DynamicMock<IGene>();
            var mockGene3 = mocks.DynamicMock<IGene>();
            using(mocks.Record())
            {
                Expect.Call(mock.RootGene).Return(mockGene1);
                Expect.Call(mockGene1.Children).Return(ListExtensions.GetObservableCollection<IGene>(mockGene2));
                Expect.Call(mockGene2.Children).Return(ListExtensions.GetObservableCollection<IGene>(mockGene3));
            }

            // action - AllGenes
            using (mocks.Playback())
            {
                var result = curElement.AllGenes.ToList();

                // Expectation - ReturnsAll3Genes
                Assert.IsTrue(result.Count() == 3
                              && result.Contains(mockGene1)
                              && result.Contains(mockGene2)
                              && result.Contains(mockGene3));
            }
        }

        [TestMethod]
        public void WithMockChromosomeAndGeneticProgramAndIoCIndividual_Clone_GetNewIndividualFromIoCWithMockParent()
        {
            // state - WithMockChromosomeAndGeneticProgramAndIoCIndividual
            var mockChromosome = mocks.DynamicMock<IChromosome>();
            var mockChromosome2 = mocks.DynamicMock<IChromosome>();
            IoC.Register<IChromosome>(mockChromosome);
            var mockGP = mocks.DynamicMock<IGeneticProgram>();
            curElement.ParentGeneticProgram = mockGP;
            var mockIndividual = mocks.DynamicMock<IIndividual>();
            IoC.Register<IIndividual>(mockIndividual);

            // Expectation - GetNewIndividualFromIoCWithMockParent
            using (mocks.Record())
            {
                mockIndividual.ParentGeneticProgram = mockGP;
                Expect.Call(mockChromosome.CloneChild(mockIndividual)).Return(mockChromosome2);
                mockIndividual.Chromosome = mockChromosome2;
            }

            // action - Clone
            var result = curElement.CloneChild();

            // verify
            Assert.IsTrue(result == mockIndividual);
            mocks.Verify(mockIndividual);
        }

        [TestMethod]
        public void WithMockGeneticProgrammingRun_ExecuteScalar_InvokesInitializeAndRootGeneChromosomeExecute()
        {
            // state - WithMockGeneticProgrammingRun
            var mock = mocks.DynamicMock<IGeneticProgrammingRun>();
            IoC.Register<IGeneticProgrammingRun>(mock);
            var mockChromosome = mocks.DynamicMock<IChromosome>();
            curElement.Chromosome = mockChromosome;
            var mockGene = mocks.DynamicMock<IGene>();

            // Expectation - MockInitializeVariablesFromUntypedListOfObjectsInvoked
            using (mocks.Record())
            {
                mock.InitializeVariablesFromUntypedListOfObjects(TestStrings.OfType<object>().ToArray());
                Expect.Call(mockChromosome.RootGene).Return(mockGene);
                Expect.Call(mockGene.Execute(mock)).Return(TestInts[0]);
            }

            // action - ExecuteScalar
            var result = curElement.ExecuteScalar<int>(TestStrings.OfType<object>().ToArray());

            // verify
            Assert.IsTrue(result == TestInts[0]);
            mocks.Verify(mock);
            mocks.Verify(mockGene);
        }
    }
}
